<?php
declare(strict_types=1);

namespace LowCode\Traits\Vue;

trait HasWatch
{

    /**
     * 基本监听 响应式状态发生变化时触发回调函数
     * @param string $watch
     * @param string $callback
     * @param array $options
     * @param string $unwatchName
     * @return $this
     */
    public function watch(string $watch, string $callback, array $options, string $unwatchName = ""): static
    {
        if ($options){
            $option = json_encode($options, JSON_UNESCAPED_UNICODE);
            $html = "watch($watch, $callback, $option)";
        }else{
            $html = "watch($watch, $callback)";
        }
        if ($unwatchName){
            $this->builder->watch->add("const $unwatchName = $html");
        }else{
            $this->builder->watch->add($html);
        }
        return $this;
    }

    /**
     * 深度监听 回调函数在所有嵌套的变更时都会被触发
     * @param string $watch
     * @param string $callback
     * @return $this
     */
    public function watchDeep(string $watch, string $callback): static
    {
        return $this->watch($watch, $callback, [
            'deep'=> true
        ]);
    }

    /**
     * 一次性侦听器 回调只在源变化时触发一次
     * @param string $watch
     * @param string $callback
     * @return $this
     */
    public function watchOnce(string $watch, string $callback): static
    {
        return $this->watch($watch, $callback, [
            'once'=> true
        ]);
    }

    /**
     * 即时回调的侦听器 创建侦听器时，立即执行一遍回调
     * @param string $watch
     * @param string $callback
     * @return $this
     */
    public function watchImmediate(string $watch, string $callback): static
    {
        return $this->watch($watch, $callback, [
            'immediate'=> true
        ]);
    }

    /**
     * 同步侦听器 在 Vue 进行任何更新之前触发
     * @param string $watch
     * @param string $callback
     * @return $this
     */
    public function watchSync(string $watch, string $callback): static
    {
        return $this->watch($watch, $callback, [
            'flush'=> "sync"
        ]);
    }

    /**
     * 响应式数据变化时同步执行
     * @param string $callback
     * @param array $options
     * @param string $unwatchName
     * @return $this
     */
    public function watchEffect(string $callback, array $options, string $unwatchName = ""): static
    {
        if ($options){
            $option = json_encode($options, JSON_UNESCAPED_UNICODE);
            $html = "watchEffect($callback, $option)";
        }else{
            $html = "watchEffect($callback)";
        }
        if ($unwatchName){
            $this->builder->watchEffect->add("const $unwatchName = $html");
        }else{
            $this->builder->watchEffect->add($html);
        }
        return $this;
    }

    protected function getWatchHtml(): string
    {
        if ($this->builder->watch->isNotEmpty()){
            $this->addVueImport("watch");
        }
        if ($this->builder->watchEffect->isNotEmpty()){
            $this->addVueImport("watchEffect");
        }
        $values1 = $this->builder->watch->all();
        $values2 = $this->builder->watchEffect->all();
        $values = array_merge($values1, $values2);
        return $this->implode($values);
    }
}
